
/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  intl_cfg.h
 *         \unit  intl
 *        \brief  This is a simple large int number calculate module config header file for C language
 *       \author  Lamdonn
 *      \version  v1.1.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#ifndef __intl_cfg_H
#define __intl_cfg_H

/* Error handling configuration */
#define INTL_E(e, c)                        do { printf("[ERROR] Code %d,%c\r\n", (e), (c)); } while (0)
// #define INTL_E(e, c)

/* 
 * With this definition, you can configure the footprint size of an intl. 
 * This is a flexible definition that can be extended to larger numbers in addition to the given few size definitions
 */

/*****************************************************************/
/*                          Config start                         */
/*****************************************************************/
// #define INTL_USE_64BITS
// #define INTL_USE_128BITS
// #define INTL_USE_256BITS
#define INTL_USE_512BITS
// #define INTL_USE_1024BITS
// #define INTL_USE_2048BITS
// #define INTL_USE_4096BITS
// #define INTL_USE_8192BITS

#if defined(INTL_USE_64BITS)
#define __INTL_BIT_PARTS__                  64
#define __INTL_U32_PARTS__                  2
#define __INTL_U16_PARTS__                  4
#define __INTL_P_MAX_BIN__                  67
#define __INTL_P_MAX_DEC__                  20
#define __INTL_P_MAX_HEX__                  19
#define __INTL_MAX__                        (intl){.u32={-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,}}
#elif defined(INTL_USE_128BITS)
#define __INTL_BIT_PARTS__                  128
#define __INTL_U32_PARTS__                  4
#define __INTL_U16_PARTS__                  8
#define __INTL_P_MAX_BIN__                  131
#define __INTL_P_MAX_DEC__                  40
#define __INTL_P_MAX_HEX__                  35
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,}}
#elif defined(INTL_USE_256BITS)
#define __INTL_BIT_PARTS__                  256
#define __INTL_U32_PARTS__                  8
#define __INTL_U16_PARTS__                  16
#define __INTL_P_MAX_BIN__                  259
#define __INTL_P_MAX_DEC__                  78
#define __INTL_P_MAX_HEX__                  67
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,}}
#elif defined(INTL_USE_512BITS)
#define __INTL_BIT_PARTS__                  512
#define __INTL_U32_PARTS__                  16
#define __INTL_U16_PARTS__                  32
#define __INTL_P_MAX_BIN__                  515
#define __INTL_P_MAX_DEC__                  155
#define __INTL_P_MAX_HEX__                  131
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
#elif defined(INTL_USE_1024BITS)
#define __INTL_BIT_PARTS__                  1024
#define __INTL_U32_PARTS__                  32
#define __INTL_U16_PARTS__                  64
#define __INTL_P_MAX_BIN__                  1027
#define __INTL_P_MAX_DEC__                  309
#define __INTL_P_MAX_HEX__                  259
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
#elif defined(INTL_USE_2048BITS)
#define __INTL_BIT_PARTS__                  2048
#define __INTL_U32_PARTS__                  64
#define __INTL_U16_PARTS__                  128
#define __INTL_P_MAX_BIN__                  2051
#define __INTL_P_MAX_DEC__                  618
#define __INTL_P_MAX_HEX__                  515
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
#elif defined(INTL_USE_4096BITS)
#define __INTL_BIT_PARTS__                  4096
#define __INTL_U32_PARTS__                  128
#define __INTL_U16_PARTS__                  256
#define __INTL_P_MAX_BIN__                  4099
#define __INTL_P_MAX_DEC__                  1234
#define __INTL_P_MAX_HEX__                  1027
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
#elif defined(INTL_USE_8192BITS)
#define __INTL_BIT_PARTS__                  8192
#define __INTL_U32_PARTS__                  256
#define __INTL_U16_PARTS__                  512
#define __INTL_P_MAX_BIN__                  8195
#define __INTL_P_MAX_DEC__                  2468
#define __INTL_P_MAX_HEX__                  2051
#define __INTL_MAX__                        (intl){.u32={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0x7FFFFFFF,}}
#define __INTL_MIN__                        (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80000000,}}
#define __INTL_ZERO__                       (intl){.u32={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}}
#endif
/*****************************************************************/
/*                          Config end                           */
/*****************************************************************/

#if 0 /* Config function */
void intl_gen_cfg(uint32_t bits, const char *filename)
{
    #define MINBITS 64
    #define NEWLINE "\n" // "\r\n" // 

    FILE* output = stdout; // Default output to standard output
    if (filename != NULL) 
    {
        output = fopen(filename, "w");
        if (output == NULL) 
        {
            fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE);
            return;
        }
    }

    /* The number of bits in an intl needs to be an exponent of two */
    if ((bits & (bits - 1)) != 0)
    {
        fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE);
        return;
    }

    /* Limiting the minimum bit */
    if (bits < MINBITS)
    {
        fprintf(stdout, "[ERROR] `bits` too small\r\b");
        return;
    }

    fprintf(output, "/*****************************************************************/"NEWLINE);
    fprintf(output, "/*                          Config start                         */"NEWLINE);
    fprintf(output, "/*****************************************************************/"NEWLINE);

    for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1)
    {
        if (tb == bits) 
        {
            fprintf(output, "#define INTL_USE_%uBITS"NEWLINE, tb);
        }
        else  
        {
            fprintf(output, "// #define INTL_USE_%uBITS"NEWLINE, tb);
        }
    }
    fprintf(output, ""NEWLINE);

    intl temp;

    for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1)
    {
        if (tb == MINBITS) 
        {
            fprintf(output, "#if defined(INTL_USE_%uBITS)"NEWLINE, tb);
        }
        else  
        {
            fprintf(output, "#elif defined(INTL_USE_%uBITS)"NEWLINE, tb);
        }

        uint32_t BIT_PARTS ; /* bits */
        uint32_t U32_PARTS ; /* __INTL_BIT_PARTS__ / 32 */
        uint32_t U16_PARTS ; /* __INTL_BIT_PARTS__ / 16 */
        uint32_t MAX_BIN   ; /* __INTL_BIT_PARTS__ + 1 */
        uint32_t MAX_DEC   ; /* strlen(intl_shl(intl(1), __INTL_BIT_PARTS__ - 1)) + 1 */
        uint32_t MAX_HEX   ; /* __INTL_BIT_PARTS__ / 4 + 1 */

        BIT_PARTS = tb;
        U32_PARTS = BIT_PARTS >> (5);
        U16_PARTS = BIT_PARTS >> (4);
        MAX_BIN = BIT_PARTS + 3; // "0b" + '\0'
        MAX_DEC = MAX_BIN; // First apply as MAX bin maximum value, and then according to the actual calculation
        MAX_HEX = (BIT_PARTS >> (2)) + 3; // "0x" + '\0'

        /* The current configuration is applied */
        if (sizeof(temp) == (bits >> 3))
        {
            char buffer[__INTL_P_MAX_BIN__];
            MAX_DEC = intl_print(intl_shl(intl(1), BIT_PARTS - 1), buffer, sizeof(buffer), "d") + 1; // '\0'
        }

        fprintf(output, "#define __INTL_BIT_PARTS__                  %u"NEWLINE, BIT_PARTS);
        fprintf(output, "#define __INTL_U32_PARTS__                  %u"NEWLINE, U32_PARTS);
        fprintf(output, "#define __INTL_U16_PARTS__                  %u"NEWLINE, U16_PARTS);
        fprintf(output, "#define __INTL_P_MAX_BIN__                  %u"NEWLINE, MAX_BIN);
        fprintf(output, "#define __INTL_P_MAX_DEC__                  %u"NEWLINE, MAX_DEC);
        fprintf(output, "#define __INTL_P_MAX_HEX__                  %u"NEWLINE, MAX_HEX);

        /* __INTL_MAX__ */
        fprintf(output, "#define __INTL_MAX__                        (intl){.u32={");
        for (uint32_t i = 0; i < U32_PARTS; i++)
        {
            fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1");
        }
        fprintf(output, "}}"NEWLINE);

        /* __INTL_MIN__ */
        fprintf(output, "#define __INTL_MIN__                        (intl){.u32={");
        for (uint32_t i = 0; i < U32_PARTS; i++)
        {
            fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x80000000" : "0");
        }
        fprintf(output, "}}"NEWLINE);

        /* __INTL_ZERO__ */
        fprintf(output, "#define __INTL_ZERO__                       (intl){.u32={");
        for (uint32_t i = 0; i < U32_PARTS; i++)
        {
            fprintf(output, "0,");
        }
        fprintf(output, "}}"NEWLINE);
    }

    fprintf(output, "#endif"NEWLINE);

    fprintf(output, "/*****************************************************************/"NEWLINE);
    fprintf(output, "/*                          Config end                           */"NEWLINE);
    fprintf(output, "/*****************************************************************/"NEWLINE);

    fprintf(stdout, "\r\n\r\n-------------------------------------------------------------\r\n"NEWLINE);

    /* The current configuration is not applied */
    if (sizeof(temp) != (bits >> 3))
    {
        fprintf(stdout, "[TODO][%s] Apply the current configuration and run it again to get the new `__INTL_P_MAX_DEC__`"NEWLINE, filename);
    }
    else  
    {
        fprintf(stdout, "[INFO][%s] The configuration has been generated, copy it to the `intl_cfg.h` range specified"NEWLINE, filename);
    }

    if (filename != NULL) 
    {
        fclose(output);
    }
}
#endif

#endif

